package com.dongzili.postgresql.common.utils;

import cn.hutool.core.annotation.AnnotationUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.index.Indexed;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 反射相关工具类
 */
public class ReflectUtils {

    /**
     * 获取不为空的属性的数据库字段名和值
     * @param obj
     * @param columns
     * @return
     */
    public static Map<String, Object> getNotNullFieldValueMap(Object obj, List<String> columns) {
        Map<String, Object> fieldValueMap = new HashMap<>();
        Class<?> clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            try {
                if(columns.contains(field.getName())){
                    continue;
                }
                field.setAccessible(true);
                Object value = field.get(obj);
                if (value != null) {
                    String fieldName = getFieldName(field);
                    fieldValueMap.put(fieldName, value);
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return fieldValueMap;
    }

    /**
     * 获取不为空的属性的数据库字段名和值
     * @param obj
     * @return
     */
    public static Map<String, Object> getNotNullFieldValueMap(Object obj) {
        Map<String, Object> fieldValueMap = new HashMap<>();
        if (obj == null){
            return fieldValueMap;
        }
        Class<?> clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                TableField tableFieldAnnotation = field.getAnnotation(TableField.class);
                if (tableFieldAnnotation != null && !tableFieldAnnotation.exist()) {
                    continue; // Ignore if exist is false
                }
                Object value = field.get(obj);
                if (value != null) {
                    if (value instanceof List<?>){
                        if(!((List<?>)value).isEmpty()){
                            fieldValueMap.put(getFieldName(field), value);
                        }
                    }else if (value instanceof String){
                        if(StringUtils.hasText(value.toString())){
                            fieldValueMap.put(getFieldName(field), value);
                        }
                    }else{
                        fieldValueMap.put(getFieldName(field), value);
                    }

                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return fieldValueMap;
    }

    public static String getFieldName(Field field) {
        TableField tableFieldAnnotation = field.getAnnotation(TableField.class);
        if (tableFieldAnnotation != null && !tableFieldAnnotation.value().isEmpty()) {
            return tableFieldAnnotation.value();
        } else {
            return field.getName();
        }
    }


    /**
     * 获取实体类上 @TableName 注解中定义的数据库表名
     * @param clazz 实体类的 Class 对象
     * @return 数据库表名，如果未找到注解或注解未设置 value 属性，则返回 null
     */
    public static String getTableName(Class<?> clazz) {
        TableName tableNameAnnotation = AnnotationUtil.getAnnotation(clazz, TableName.class);
        if (tableNameAnnotation != null) {
            return tableNameAnnotation.value();
        }
        return "";
    }

    /**
     * 获取实体字段上 @TableField 注解中定义的列名
     * @param clazz
     * @return
     */
    public static String getColumnNames(Class<?> clazz) {
        List<String> columns = new ArrayList<>();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            if (field.isAnnotationPresent(TableField.class)) {
                TableField tableFieldAnnotation = field.getAnnotation(TableField.class);
                if(tableFieldAnnotation!=null && tableFieldAnnotation.exist()){
                    columns.add(tableFieldAnnotation.value()+" as `"+field.getName()+"`");
                }

            }else if(field.isAnnotationPresent(TableId.class)){
                TableId tableFieldAnnotation = field.getAnnotation(TableId.class);
                if(tableFieldAnnotation!=null){
                    columns.add(tableFieldAnnotation.value()+" as `"+field.getName()+"`");
                }
            }
            else{
                columns.add("`"+field.getName()+"`");
            }
        }
        return String.join(",", columns);
    }

    /**
     * 获取主键数据库字段名称
     * @param clazz
     * @return
     */
    public static String getPrimaryColumnKey(Class<?> clazz) {

        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            if (field.isAnnotationPresent(TableId.class)) {
                TableId tableFieldAnnotation = field.getAnnotation(TableId.class);
                if(tableFieldAnnotation!=null){
                    return tableFieldAnnotation.value();
                }

            }
        }
        return "id";
    }
    public static Field getPrimaryField(Class<?> clazz) {

        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            if (field.isAnnotationPresent(TableId.class) || field.isAnnotationPresent(Id.class) || field.isAnnotationPresent(Indexed.class) || field.getName().equalsIgnoreCase("id")) {
                TableId tableFieldAnnotation = field.getAnnotation(TableId.class);
                if(tableFieldAnnotation!=null){
                    return field;
                }

            }
        }
        return null;
    }
    /**
     * 获取主键实体字段名称
     * @param clazz
     * @return
     */
    public static String getPrimaryFieldKey(Class<?> clazz) {
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            if (field.isAnnotationPresent(TableId.class)) {
                TableId tableFieldAnnotation = field.getAnnotation(TableId.class);
                if(tableFieldAnnotation!=null){
                    return field.getName();
                }

            }
        }
        return "id";
    }


    public static <T> Object getPrimaryValue(Class<T> clazz, T entity) throws IllegalAccessException {

        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            if (field.isAnnotationPresent(TableId.class)) {
                TableId tableFieldAnnotation = field.getAnnotation(TableId.class);
                if(tableFieldAnnotation!=null){
                    return field.get(entity);
                }

            }
        }
        return null;
    }

    /**
     * 获取实体类的主键值
     */
    public static <T> Object getPrimaryValue(T entity) {
        try{
            Field[] fields = entity.getClass().getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                if (field.isAnnotationPresent(TableId.class) || field.isAnnotationPresent(Id.class) || field.getName().equalsIgnoreCase("id")) {
                    return field.get(entity);
                }
            }
        }catch (Exception e){
            return null;
        }
        return null;
    }


    public static <T> T setPrimaryValue(Class<T> clazz, Object value) throws IllegalAccessException, InstantiationException {

        T cloneEntity = clazz.newInstance();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            if (field.isAnnotationPresent(TableId.class)) {
                TableId tableFieldAnnotation = field.getAnnotation(TableId.class);
                if(tableFieldAnnotation!=null){
                    field.set(cloneEntity, value);
                    return cloneEntity;
                }

            }
        }
        return null;
    }

    public static <T> T setPrimaryValue(T entity, Object value) throws IllegalAccessException, InstantiationException {

//        T cloneEntity = entity.getClass().newInstance();
        Field[] fields = entity.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            if (field.isAnnotationPresent(TableId.class)) {
                TableId tableFieldAnnotation = field.getAnnotation(TableId.class);
                if(tableFieldAnnotation!=null){
                    field.set(entity, value);
                    return entity;
                }

            }
        }
        return null;
    }

    public static <T> void setValue(T entity, Map<String, Object> map) throws IllegalAccessException, InstantiationException {

//        T cloneEntity = entity.getClass().newInstance();
        Field[] fields = entity.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            if (map.containsKey(field.getName())) {
                field.set(entity, map.get(field.getName()));
            }
        }
    }

    public static <T> T getObjByKeys(Class<T> clazz, T entity){
        try{
            Object id = getPrimaryValue(clazz, entity);
            if(id != null){
                return setPrimaryValue(clazz, id);
            }
            T cloneEntity = clazz.newInstance();
            Field[] fields = clazz.getDeclaredFields();
            boolean hasKey = false;
            // 遍历所有属性
            for (Field field : fields) {
                // 如果属性上有此注解，则进行赋值操作
                if (field.isAnnotationPresent(TableId.class)) {
                    field.setAccessible(true);
                    Object value = field.get(entity);
                    field.set(cloneEntity, value);
                    hasKey = true;
                }
            }
            return hasKey ? cloneEntity : null;
        }catch (Exception e){
            return null;
        }
    }


    /**
     * 根据字段获取数据库字段名称
     * @param clazz
     * @param fieldName
     * @return
     * @param <E>
     */
    public static <E> String getColumnName(Class<E> clazz, String fieldName) {
        try {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                if(field.getName().equals(fieldName)){
                    if(field.isAnnotationPresent(TableField.class)){
                        TableField tableFieldAnnotation = field.getAnnotation(TableField.class);
                        if(tableFieldAnnotation!=null){
                            return tableFieldAnnotation.value();
                        }
                    }else{
                        return field.getName();
                    }
                }
            }
        }catch (Exception e){
            return null;
        }
        return null;
    }


}
